package com.hnx.admin.aurora.utils;

import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
创建人： 倔强的头发
创建时间：2025/6/17
功能描述:

*/
public class IPUtil {
    private static final String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
    private static final String proxyHeader = "X-Forwarded-For";
    private static final Integer maxProxyLevel = 3;
    private static final String SLASH = "/";
    public static final String LOCAL_IP = "127.0.0.1";
    public final static Pattern IPV4 = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)$");
    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
    public static String getClientIp(HttpServletRequest request) {
        for (String header : headers) {
            String value = request.getHeader(header);
            if (StringUtils.hasText(value)) {
                String ip = parseIpFromHeader(value, header, proxyHeader, maxProxyLevel);
                if (isValidIp(ip)) {
                    return ip;
                }
            }
        }
        String ipaddr = request.getRemoteAddr();
        return ipaddr.equals("0:0:0:0:0:0:0:1") ? LOCAL_IP : ipaddr;
    }

    private static String parseIpFromHeader(String headerValue, String headerName, String proxyHeader, int maxProxyLevel) {
        String[] ips = headerValue.split(",");
        List<String> ipList = new ArrayList<>();
        for (String ip : ips) {
            ip = ip.trim();
            if (StringUtils.hasText(ip) && !"unknown".equalsIgnoreCase(ip)) {
                ipList.add(ip);
            }
        }
        if (headerName.equalsIgnoreCase(proxyHeader)) {
            int index = ipList.size() - maxProxyLevel;
            if (index <= 0) {
                return ipList.get(0);
            } else {
                return ipList.get(index - 1);
            }
        } else {
            return ipList.get(0);
        }
    }

    private static boolean isValidIp(String ip) {
        if (StringUtils.hasText(ip)) {
            return ip.matches("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$") || ip.matches("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
        }
        return false;
    }
    public static boolean isInRange(String ip, String cidr) {
        final int maskSplitMarkIndex = cidr.lastIndexOf(SLASH);
        if (maskSplitMarkIndex < 0) {
            throw new IllegalArgumentException("Invalid cidr: " + cidr);
        }

        final long mask = (-1L << 32 - Integer.parseInt(cidr.substring(maskSplitMarkIndex + 1)));
        long cidrIpAddr = ipv4ToLong(cidr.substring(0, maskSplitMarkIndex));

        return (ipv4ToLong(ip) & mask) == (cidrIpAddr & mask);
    }

    public static boolean matchIP(String ip, List<String> ips) {
        Integer len = ips.size();
        boolean flag = false;
        for (int i = 0; i < len; i++) {
            String ipi = ips.get(i);
            if (ipi.indexOf("/") >= 0) {
                flag = isInRange(ip, ipi);
                if (flag) return true;
            }
            if (ipi.indexOf("-") >= 0 || ipi.indexOf("~") >= 0) {
                String[] split = ipi.split("-").length == 1 ? ipi.split("~") : ipi.split("-");
                String startIp = split[0];
                String endIp = split[1];
                long ipLong = ipv4ToLong(ip);
                long startIpLong = ipv4ToLong(startIp);
                long endIpLong = ipv4ToLong(endIp);
                flag = (ipLong >= startIpLong) && (ipLong <= endIpLong);
                if (flag) return true;
            }
            if (ipi.indexOf("*") >= 0) {
                flag = ipi.matches(REGX_IP_WILDCARD);
                if (flag) return true;
            }
            flag = ip.equals(ipi);
            if (flag) return true;
        }
        return flag;
    }

    /**
     * 根据ip地址(xxx.xxx.xxx.xxx)计算出long型的数据
     * 方法别名：inet_aton
     *
     * @param strIP IP V4 地址
     * @return long值
     */
    public static long ipv4ToLong(String strIP) {
        final Matcher matcher = IPV4.matcher(strIP);
        if (matcher.matches()) {
            return matchAddress(matcher);
        }
        throw new IllegalArgumentException("Invalid IPv4 address!");
    }

    private static long matchAddress(Matcher matcher) {
        long addr = 0;
        for (int i = 1; i <= 4; ++i) {
            addr |= Long.parseLong(matcher.group(i)) << 8 * (4 - i);
        }
        return addr;
    }

    /**
     * 判定是否为内网IPv4<br>
     * 私有IP：
     * <pre>
     * A类 10.0.0.0-10.255.255.255
     * B类 172.16.0.0-172.31.255.255
     * C类 192.168.0.0-192.168.255.255
     * </pre>
     * 当然，还有127这个网段是环回地址
     *
     * @param ipAddress IP地址
     * @return 是否为内网IP
     * @since 5.7.18
     */
    public static boolean isInnerIP(String ipAddress) {
        boolean isInnerIp;
        long ipNum = ipv4ToLong(ipAddress);

        long aBegin = ipv4ToLong("10.0.0.0");
        long aEnd = ipv4ToLong("10.255.255.255");

        long bBegin = ipv4ToLong("172.16.0.0");
        long bEnd = ipv4ToLong("172.31.255.255");

        long cBegin = ipv4ToLong("192.168.0.0");
        long cEnd = ipv4ToLong("192.168.255.255");

        isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || LOCAL_IP.equals(ipAddress);
        return isInnerIp;
    }

    /**
     * 指定IP的long是否在指定范围内
     *
     * @param userIp 用户IP
     * @param begin  开始IP
     * @param end    结束IP
     * @return 是否在范围内
     */
    private static boolean isInner(long userIp, long begin, long end) {
        return (userIp >= begin) && (userIp <= end);
    }
}
